﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ServiceModel;
using NHibernate;
using BrokerBase.Lib.Client;
using Broker.Model;
using Broker.Comm;
using System.Windows;
using BrokerBase.Lib.DataBase;
using System.Data;
using Broker.DataService;

namespace Broker.Update
{

    public enum RemoteDataServiceState {NoConnect=0, Connecting=1,Received=2 }

    public delegate void ClientRegInfoChangedHandler(ClientDataInfo info);
    public delegate void ClientScoreInfoReceivedHandler();
    public delegate void ConnectStateChangedHandler(RemoteDataServiceState state);
    public class RemoteDataService
    {
        public event ConnectStateChangedHandler ConnectStateChanged;
        public event ClientRegInfoChangedHandler ClientRegInfoChanged;
        public event ClientScoreInfoReceivedHandler ClientScoreReceived;

        private static volatile bool shouldStop;//如果线程检查到该变量为true 则终止。 

        public const string DATAUPDATE_SERVICE_NAME = "DataUpdateService";
        public const string LICENSE_SERVICE_NAME = "licenseService";

        private const int MAX_LENGTH = 256 * 1024 * 1024;//256M的最大数据
        private const int SLEEP_TIME = 1000 * 60;//间隔1分钟连接一次服务器

        private static Thread thread;

        private ISessionFactory hbmSessionFactory;

        private RegistrantInfo regInfo;
        private TerminalInfo terInfo;

        private static App app = (App)Application.Current;

        private volatile object syncState = new object();
        private RemoteDataServiceState state;

        private volatile object syncIsNewReg=new object();
        private bool isNewReg;

        public volatile object syncUser = new object();

        public SysUser user;

        private RemoteDataService()
        {
            regInfo = LicenseInfo.GetInstance().CreateRegistrantInfo();
            terInfo = ClientUtil.CreateTerminalInfo();

            hbmSessionFactory = AppGlobal.HbmSessionFactory;
        }

        public static RemoteDataService GetInstance()
        {
            return new RemoteDataService();
        }

        public void Start()
        {

            thread = new Thread(LoopWork);
            app.Exit += new ExitEventHandler(app_Exit);
            thread.IsBackground = true;
            thread.Start();
        }

        void app_Exit(object sender, ExitEventArgs e)
        {
            
            shouldStop = true;//线程终止标志
        }

        private void LoopWork()
        {
            try
            {
                ChannelFactory<IDataService> channelFacotry = null;

                DateTime workTime = DateTime.MinValue;//

                while (!shouldStop)
                {
                    TimeSpan span = DateTime.Now.Subtract(workTime);

                    bool isExistRegUser=!string.IsNullOrEmpty(regInfo.UserName);

                    try
                    {
                        State = RemoteDataServiceState.Connecting;

                        channelFacotry = AppGlobal.CreateDataServiceFactory();
                        channelFacotry.Open();

                        IDataService ser = channelFacotry.CreateChannel();

                        GetClientRegInfo(ser, hbmSessionFactory);

                        GetScoreInfo(ser, hbmSessionFactory);

                        if (channelFacotry.State == CommunicationState.Opened)
                        {
                            channelFacotry.Close();
                        }

                        if (User != null)
                        {
                            Thread.Sleep(SLEEP_TIME * 15);
                        }
                        else
                        {
                            Thread.Sleep(SLEEP_TIME * 30);
                        }
                    }
                    catch (ThreadInterruptedException tex)
                    {
                        AppGlobal.Log.Error("立即执行后台服务线程", tex);
                        State = RemoteDataServiceState.Connecting;

                        if (ConnectStateChanged != null)
                        {
                            ConnectStateChanged(RemoteDataServiceState.Connecting);
                        }
                    }
                    catch (Exception ex)
                    {
                        State = RemoteDataServiceState.NoConnect;
                        channelFacotry.Abort();

                        AppGlobal.Log.Error("数据更新检查错误", ex);

                        Thread.Sleep(SLEEP_TIME * 3);
                    } 
                }
            }
            catch (Exception ex)
            {
                AppGlobal.Log.Error("后台连接服务端出错", ex);
            }
        }

        private void GetClientRegInfo(IDataService ser, ISessionFactory sessFactory)
        {
            ISession sess=null;
            try
            {
                sess = sessFactory.OpenSession();

                IList<long> maxTss = sess.CreateSQLQuery("select max(LastTimeStamp) from System_TableUpdate where IsNeedUpdate=1 group by TableType").List<long>();

                string result = null;
                
                lock (syncUser)
                {
                    result = ser.GetClientInfo(regInfo.GetData(), terInfo.GetData(), maxTss[0], maxTss[1]);
                }
                ClientDataInfo clientRegInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<ClientDataInfo>(result);

                State = RemoteDataServiceState.Received;

                AppGlobal.ResultClientRegInfo = clientRegInfo;

                if (ClientRegInfoChanged != null)
                {
                    ClientRegInfoChanged(clientRegInfo);
                }
            }
            catch (Exception ex)
            {
                AppGlobal.Log.Error("GetClientRegInfo", ex);
            }
            finally
            {
                if (sess != null && sess.IsOpen)
                {
                    sess.Close();
                }
            }
        }

        public void GetScoreInfo(IDataService ser, ISessionFactory sessFactory)
        {
            ISession sess = null;
            ITransaction tx = null;
            try
            {
                sess = sessFactory.OpenSession();

                long clientTs = ScoreInfo.LoadMax(sess);

                string serverTsResult = ser.GetScoreRecordMaxTs(regInfo.GetData(), terInfo.GetData());
                long serverTs = Newtonsoft.Json.JsonConvert.DeserializeObject<long>(serverTsResult);

                if (serverTs > clientTs)
                {
                    string recResult = null;
                    lock (syncUser)
                    {
                        recResult = ser.GetScoreRecord(regInfo.GetData(), terInfo.GetData(), clientTs);
                    }
                    IList<ScoreRecordInfo> recs = Newtonsoft.Json.JsonConvert.DeserializeObject<IList<ScoreRecordInfo>>(recResult);

                    try
                    {
                        tx = sess.BeginTransaction();

                        foreach (ScoreRecordInfo s in recs)
                        {
                            sess.SaveOrUpdate(s);
                        }

                        tx.Commit();

                    }
                    catch (Exception ex)
                    {
                        if (tx != null)
                        {
                            tx.Rollback();
                        }
                    }
                    finally
                    {
                        if (sess != null)
                        {
                            sess.Close();
                        }
                    }

                    IsNewReg = true;
                    if (ClientScoreReceived != null)
                    {
                        ClientScoreReceived();
                    }
                }


            }
            catch (Exception ex)
            {
                AppGlobal.Log.Error("获取积分时发生错误", ex);
            }
        }

        public RemoteDataServiceState State
        {
            get
            {
                lock (syncState)
                {
                    return state;
                }
            }

            set
            {
                lock (syncState)
                {
                    this.state = value;
                }
            }
        }

        public bool IsNewReg
        {
            get
            {
                lock (syncIsNewReg)
                {
                    return isNewReg;
                }
            }

            set
            {
                lock (syncIsNewReg)
                {
                    this.isNewReg = value;
                }
            }
        }

        public SysUser User
        {
            get
            {
                lock (syncUser)
                {
                    return user;
                }
            }
            set
            {
                lock (syncUser)
                {
                    this.user = value;
                    LicenseInfo licInfo = LicenseInfo.GetInstance();
                    regInfo = licInfo.CreateRegistrantInfo();
                    terInfo = ClientUtil.CreateTerminalInfo();
                }
            }
        }


        public void ClientRegInfoUpdated()
        {
            AppGlobal.ResultClientRegInfo.IsNewData = false;

            if(ClientRegInfoChanged!=null)
                ClientRegInfoChanged(AppGlobal.ResultClientRegInfo);
        }


        public void ImmediateRun()
        {
            lock(syncUser)
            {
                thread.Interrupt();
            }
        }

    }
}
